<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <script>
      (function(){
        const WIDTH = 2000, HEIGHT = 2000, SCALE = 0.5

        const canvas = document.createElement('canvas')
        canvas.width = WIDTH
        canvas.height = HEIGHT
        canvas.style.width = WIDTH * SCALE + 'px'
        canvas.style.height = HEIGHT * SCALE + 'px'
        document.body.appendChild(canvas)
        const gl = canvas.getContext('webgl2')

        function createShaderProgram(vertSource, fragSource) {
          function compileShader(shader, name) {
            gl.compileShader(shader)
            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
              throw new Error('COMPILATION ERROR (' + name + '):\n' + gl.getShaderInfoLog(shader))
            }
          }

          function linkShader(program) {
            gl.linkProgram(program)
            if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
              throw new Error('LINKING ERROR:\n' + gl.getProgramInfoLog(program))
            }
          }

          const vShader = gl.createShader(gl.VERTEX_SHADER)
          const fShader = gl.createShader(gl.FRAGMENT_SHADER)

          gl.shaderSource(vShader, vertSource)
          gl.shaderSource(fShader, fragSource)
          compileShader(vShader, 'VERTEX SHADER')
          compileShader(fShader, 'FRAGMENT SHADER')

          const program = gl.createProgram()
          gl.attachShader(program, vShader)
          gl.attachShader(program, fShader)
          linkShader(program)

          gl.deleteShader(vShader)
          gl.deleteShader(fShader)

          return program
        }

        const program = createShaderProgram(
`#version 300 es

layout (location = 0) in vec2 pos;

out vec2 tpos;

void main()
{
  gl_Position = vec4(pos.xy, 0.0, 1.0);
  tpos = pos * 2.0;
}
`,
`#version 300 es

precision mediump float;

in vec2 tpos;

out vec4 result;

void main()
{
  vec2 z = vec2(0.0, 0.0);
  for (int n = 0; n < 1000; n++)
    z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + tpos;
  if (dot(z, z) < 4.0)
    result = vec4(1.0, 1.0, 1.0, 1.0);
  else
    result = vec4(0.0, 0.0, 0.0, 1.0);
}
`
        )

        const posBuffer = gl.createBuffer()
        gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer)
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
          1, 1, -1, 1, 1, -1, -1, -1
        ]), gl.STATIC_DRAW)
        gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0)
        gl.enableVertexAttribArray(0)

        gl.useProgram(program)
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
      }())
    </script>
  </body>
</html>
